﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace MvcToolbox
{
    /// <summary>
    /// Class GridBoundColumn
    /// </summary>
    /// <typeparam name="TModel">The type of the T model.</typeparam>
    /// <typeparam name="TValue">The type of the T value.</typeparam>
    /// <typeparam name="T">The type of the property</typeparam>
    public class GridBoundColumn<TModel, TValue, T> : GridColumn<TModel, TValue>
    {
        /// <summary>
        /// The MVC grid
        /// </summary>
        private IMvcGrid<TModel, TValue> mvcGrid;

        /// <summary>
        /// Initializes a new instance of the <see cref="GridBoundColumn{TModel, TValue, T}"/> class.
        /// </summary>
        /// <param name="mvcGrid">The MVC grid.</param>
        /// <param name="expression">The expression.</param>
        public GridBoundColumn(IMvcGrid<TModel, TValue> mvcGrid, System.Linq.Expressions.Expression<Func<TValue, T>> expression)
        {
            // TODO: Complete member initialization
            this.mvcGrid = mvcGrid;
            this.Expression = expression;
            this.MetaData = ModelMetadata.FromLambdaExpression<TValue, T>(this.Expression, this.mvcGrid.ViewData);
        }

        /// <summary>
        /// Gets or sets the expression.
        /// </summary>
        /// <value>The expression.</value>
        public System.Linq.Expressions.Expression<Func<TValue, T>> Expression { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is hide.
        /// </summary>
        /// <value><c>true</c> if this instance is hide; otherwise, <c>false</c>.</value>
        public override bool IsHide { get; set; }

        /// <summary>
        /// Gets or sets the template.
        /// </summary>
        /// <value>The template.</value>
        public override string Template { get; set; }

        /// <summary>
        /// Gets or sets the width.
        /// </summary>
        /// <value>The width.</value>
        public override int Width { get; set; }

        /// <summary>
        /// Gets or sets the format.
        /// </summary>
        /// <value>The format.</value>
        public override string Format { get; set; }


        public System.Linq.Expressions.Expression<Func<TValue, T>> FormatExpression { get; set; }

        /// <summary>
        /// Gets the header.
        /// </summary>
        /// <value>The header.</value>
        public override string Header
        {
            get
            {
                return this.MetaData.DisplayName ?? (this.MetaData.PropertyName ?? ExpressionHelper.GetExpressionText(this.Expression));
            }
        }

        /// <summary>
        /// Gets the name of the property.
        /// </summary>
        /// <value>The name of the property.</value>
        public override string PropertyName
        {
            get
            {
                return this.MetaData.PropertyName;
            }
        }

        /// <summary>
        /// Gets or sets the meta data.
        /// </summary>
        /// <value>The meta data.</value>
        private ModelMetadata MetaData { get; set; }

        /// <summary>
        /// Renders the specified control.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <param name="html">The HTML.</param>
        /// <param name="prop">The prop.</param>
        public override void Render(StringBuilder control, HtmlHelper<TModel> html, ModelMetadata prop, ModelMetadata viewData)
        {
            string cssClass = this.IsHide ? " class='hide' " : string.Empty;

            string style = this.Width > 0 ? " style='width:" + this.Width + "px' " : string.Empty;

            control.Append(@"<td " + cssClass + style + ">");
            var uihint = prop.TemplateHint;
            if (string.IsNullOrEmpty(uihint))
            {
                if (string.IsNullOrEmpty(this.Format))
                {
                    if (string.IsNullOrEmpty(this.Template))
                    {
                        try
                        {
                            control.Append(html.DisplayFor(p => prop.Model));
                        }
                        catch (Exception ex)
                        {
                            control.Append(prop.Model);
                        }
                    }
                    else
                    {
                        control.Append(string.Format(this.Template, prop.Model == null ? string.Empty : prop.Model.ToString()));
                    }
                }
                else
                {
                    if (FormatExpression != null)
                    {
                        var propTmp = viewData.Properties.Where(pm => pm.PropertyName == (FormatExpression.Body as MemberExpression).Member.Name).SingleOrDefault();
                        control.Append(string.Format(this.Format, prop.Model == null ? string.Empty : prop.Model, propTmp.Model));
                    }
                    else
                    {
                        control.Append(string.Format(this.Format, prop.Model == null ? string.Empty : prop.Model));
                    }
                } 
            }
            else
            {
                try
                {
                    control.Append(html.DisplayFor(p => prop.Model, uihint));
                }
                catch (Exception ex)
                {
                    control.Append(prop.Model);
                }
            }

            control.Append(@"</td>");
        }
    }
}
